package com.jp.fm.dao;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;

import java.io.IOException;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;

import net.sf.ehcache.Cache;

import org.junit.Before;
import org.junit.Test;

import com.jp.fm.HomeFinanceRunner;
import com.jp.fm.TestHelper;
import com.jp.fm.data.Account;
import com.jp.fm.data.AccountType;

public class AccountDaoTest {

	AccountDao accountDao = null;

	@Before
	public void setUp() throws IOException {
		TestHelper.setupTestDb();

		accountDao = new AccountDao();

		// Clear cache
		HomeFinanceRunner.getCache(AccountDao.CACHE_NAME).removeAll();
	}

	@Test
	public final void testFindByType() {
		List<Account> list = accountDao.findByType(new AccountType(1,
				"Credit Cards", 0));

		assertNotNull(list);
		assertEquals(2, list.size());
	}

	@Test
	public final void testFindAverageAccountBalanceForRange() {

		Calendar cal1 = new GregorianCalendar(2013, 0, 1);
		Calendar cal2 = new GregorianCalendar(2013, 2, 1);

		Float ret = accountDao.findAverageAccountBalanceForRange(
				cal1.getTime(), cal2.getTime(), new Account(null,
						"Checking Account", null, null, null, null, 0));

		assertNotNull(ret);
		assertEquals(Float.valueOf("150.00"), ret);
	}

	@Test
	public final void testFindAllSuccess() {
		List<Account> list = accountDao.findAll();

		assertNotNull(list);
		assertEquals(3, list.size());
	}

	@Test
	public final void testFindByNameSuccess() {
		Account acct = accountDao.findByName("Checking Account");

		assertNotNull(acct);
		assertEquals(Long.valueOf("1111"), acct.getAccountNumber());
		assertEquals("Checking Account", acct.getName());
	}

	@Test
	public final void testWriteAccountBalanceSame() {

		Account acct = accountDao.findByName("Checking Account");
		acct.setBalance(Float.valueOf("10.99"));
		Calendar cal = new GregorianCalendar(2013, Calendar.MARCH, 13);

		// Insert new balance
		accountDao.writeObject(acct);

		// Should not insert new balance in same week
		Cache cache = HomeFinanceRunner.getCache(AccountDao.CACHE_NAME);
		cache.removeAll();
		acct = accountDao.findByName("Checking Account");
		acct.setBalance(Float.valueOf("10.99"));
		Integer sameBalId = accountDao.writeAccountBalance(acct, cal.getTime());

		cache = HomeFinanceRunner.getCache(AccountDao.CACHE_NAME);
		cache.removeAll();
		acct = accountDao.findByName("Checking Account");

		assertEquals(acct.getAccountBalance().getId(), sameBalId);
	}

	@Test
	public final void testWriteAccountBalanceByDate() {

		Account acct = accountDao.findByName("Checking Account");

		Float curBal = acct.getBalance();
		Integer curBalId = acct.getAccountBalance().getId();

		acct.setBalance(curBal);
		accountDao.writeObject(acct);

		Cache cache = HomeFinanceRunner.getCache(AccountDao.CACHE_NAME);
		cache.removeAll();

		Account acct2 = accountDao.findByName("Checking Account");
		Integer newBalId = acct2.getAccountBalance().getId();
		Float newBal = acct2.getBalance();

		assertNotEquals(curBalId, newBalId);
		assertEquals(curBal, newBal);
	}

	@Test
	public final void testWriteObjectSuccess() {

		// First, test inserting a new account balance record
		Account acct = accountDao.findByName("Checking Account");
		acct.setBalance(Float.valueOf("150.00"));
		accountDao.writeObject(acct);

		Cache cache = HomeFinanceRunner.getCache(AccountDao.CACHE_NAME);
		cache.removeAll();

		acct = accountDao.findByName("Checking Account");
		assertEquals(Float.valueOf("150.00"), acct.getBalance());

		// Second, test with no record inserted based on date and
		// same balance
		acct.setBalance(Float.valueOf("150.00"));
		accountDao.writeObject(acct);
		cache = HomeFinanceRunner.getCache(AccountDao.CACHE_NAME);
		cache.removeAll();
		acct = accountDao.findByName("Checking Account");
		assertEquals(Float.valueOf("150.00"), acct.getBalance());

		// Third, test new record inserted based on balance
		// change even if the date is the same
		acct.setBalance(Float.valueOf("200.00"));
		accountDao.writeObject(acct);
		cache = HomeFinanceRunner.getCache(AccountDao.CACHE_NAME);
		cache.removeAll();
		acct = accountDao.findByName("Checking Account");
		assertEquals(Float.valueOf("200.00"), acct.getBalance());
	}
}
